package com.sicpa.common.utils.html2pdf;

import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.apache.pdfbox.multipdf.Splitter;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.http.*;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

/**
 * pdf预览截取、转图片、下载等功能
 */
public class PDFUtil {

    /**
     * 根据传入的网络截取指定起止页数的PDF，并保存为一个新的pdf
     * @param startPage 从1开始计数，即第一页
     * @param endPage
     * @param netUrl 网络文件路径
     * @param source 本地文件路径
     * @param dest 输出文件路径
     * @return
     */
    public static String splitPdf2File(int startPage,int endPage,String netUrl, String source, String dest) {
        try {
            PDDocument document = new PDDocument();
            ListIterator<PDDocument> iterator = splitPDDoc(document,startPage,endPage,netUrl,source).listIterator();
            PDFMergerUtility PDFMerger = new PDFMergerUtility();
            PDFMerger.setDestinationFileName(dest);
            setPDFMerger(PDFMerger,iterator);
            PDFMerger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
            document.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据传入的网络截取指定起止页数的PDF，并返回一个输出流，上层方法可基于输出流进行进一步操作
     * @param startPage 从1开始计数，即第一页
     * @param endPage
     * @param netUrl 网络文件路径
     * @param source 本地文件路径
     * @return
     */
    public static OutputStream splitPdf2Byte(int startPage,int endPage, String netUrl, String source) {
        try {
            PDDocument document = new PDDocument();
            ListIterator<PDDocument> iterator = splitPDDoc(document,startPage,endPage,netUrl,source).listIterator();
            ByteArrayOutputStream destOutStream = new ByteArrayOutputStream();
            PDFMergerUtility PDFMerger = new PDFMergerUtility();
            PDFMerger.setDestinationStream(destOutStream);
            setPDFMerger(PDFMerger,iterator);
            PDFMerger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
            document.close();
            return destOutStream;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static void setPDFMerger(PDFMergerUtility PDFMerger, ListIterator<PDDocument> iterator) throws IOException {
        while(iterator.hasNext()){
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            PDDocument pd = iterator.next();
            pd.save(outputStream);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            PDFMerger.addSource(inputStream);
            pd.close();
            iterator.next().close();
        }
    }

    /**
     * 获取pdf文件或输入流，并根据指定页数进行分割
     * @param startPage
     * @param endPage
     * @param netUrl
     * @param source
     * @return
     * @throws Exception
     */
    private static List<PDDocument> splitPDDoc(PDDocument document, int startPage, int endPage, String netUrl, String source) throws Exception {
        if(startPage < 0 || startPage > endPage){
            throw new Exception("startPage or endPage is wrong");
        }
        if(!StringUtils.isEmpty(netUrl)){
            document = PDDocument.load(downloadPdf(netUrl));
        }else{
            File indexFile = new File(source);
            document = PDDocument.load(indexFile);
        }
        if(document != null && document.getNumberOfPages() >= endPage){
            System.out.println("origin_pages:" + document.getNumberOfPages());
            Splitter splitter = new Splitter();
            splitter.setStartPage(startPage);
            splitter.setEndPage(endPage);
            List<PDDocument> pages = splitter.split(document);
            return pages;
        }else{
            throw new Exception("document is empty or not enough pages");
        }

    }

    /**
     * 从网络下载PDF文件，并已流的方式返回
     * @param fileUrl
     * @return
     */
    public static InputStream downloadPdf(String fileUrl){
        InputStream inputStream = null;
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_PDF));
        ResponseEntity<byte[]> response = restTemplate.exchange(
                fileUrl,
                HttpMethod.GET,
                new HttpEntity<byte[]>(headers),
                byte[].class
        );
        byte[] result = response.getBody();
        inputStream = new ByteArrayInputStream(result);
        return inputStream;
    }


    /**
     * pdf转图片，默认转换出的是png格式，且似乎只能一页一页的转，renderer中要设置转的是第几页，从0开始
     * 所以如果想把整个pdf都转的话，那应该是需要转换之后，再进行图片合并操作
     * @param pdfStream
     * @return
     * @throws Exception
     */
    public static ByteArrayOutputStream pdfStream2Image(InputStream pdfStream) throws Exception {
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        PDDocument doc = PDDocument.load(pdfStream);
        PDFRenderer renderer = new PDFRenderer(doc);
        int pageCount = doc.getNumberOfPages();
        if (pageCount > 0) {
            BufferedImage image = renderer.renderImage(0, 4.0f);
            image.flush();
            ImageOutputStream imOut;
            imOut = ImageIO.createImageOutputStream(bs);
            ImageIO.write(image, "png", imOut);
            doc.close();
            imOut.close();
        }else{
            throw new Exception("pdf is empty");
        }
        return bs;
    }


    public static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        inStream.close();
        return outStream.toByteArray();
    }


}
